const util = require('util')
const jwt = require('jsonwebtoken')
const verify = util.promisify(jwt.verify)
// const pathToRegexp = require('path-to-regexp')

const KEY = 'user'
const LOGIN_URL = '/login'

/**
 * jwt验证
 */
exports.jwtAuth = (options) => {
  const { secret, jwtName, loginUrl, ignore, intercept, allowSession } = {
    jwtName: KEY,
    loginUrl: LOGIN_URL,
    ignore: [LOGIN_URL],
    intercept: [],
    // 没有传递token时，允许使用session代替，名称必须一样
    allowSession: true,
    ...options,
  }

  if (!secret) throw new Error('请传递秘钥')

  return async (ctx, next) => {
    const { url } = ctx

    if (skipAuth(ignore, intercept, url)) return await next()

    // 获取jwt
    const token = ctx.header.authorization

    const data = {}
    if (loginUrl) data.loginUrl = loginUrl

    if (token) {
      try {
        ctx.state[jwtName] = await verify(token, secret)
      } catch (e) {
        return (ctx.body = {
          code: 401,
          msg: '请重新登录',
          data,
        })
      }

      await next()
    } else {
      // 调试模式下 支持用session代替token
      // if (config.env == 'development') {
      if (allowSession) {
        if (ctx.session) {
          const state = ctx.session[jwtName]

          if (state) {
            ctx.state[jwtName] = state
            await next()
            return
          }
        }
      }

      ctx.body = {
        code: 401,
        msg: '请先登录',
        data,
      }
    }
  }
}

/**
 * 前台session验证
 */
exports.sessionAuth = (options) => {
  options = {
    sessionName: KEY,
    loginUrl: LOGIN_URL,
    ignore: [LOGIN_URL],
    intercept: [],
    ...options,
  }

  const { sessionName, ignore, intercept } = options

  return async (ctx, next) => {
    const { url } = ctx

    if (skipAuth(ignore, intercept, url)) return await next()

    const { session, method } = ctx

    // 获取用户
    const user = session[sessionName]

    const loginUrl = `${options.loginUrl}?backUrl=` + encodeURIComponent(ctx.originalUrl)

    if (user) {
      ctx.state[sessionName] = user

      await next()
    } else {
      if (method == 'POST') {
        ctx.body = {
          code: 401,
          msg: '请先登录',
          data: {
            loginUrl,
          },
        }
      } else {
        ctx.redirect(loginUrl)
      }
    }
  }
}

/**
 * 判断是否跳过授权(url没有被拦截或过滤时)
 * @param {*} ignore
 * @param {*} intercept
 * @param {*} url
 */
function skipAuth(ignore, intercept, url) {
  // 判断URL是否过滤
  if (ignore && ignore.length) {
    const ret = urlMatch(ignore, url)

    // 匹配到拦截url
    if (ret) return true
  }

  // 判断URL是否拦截
  if (intercept && intercept.length) {
    const ret = urlMatch(intercept, url)

    // 没有匹配到拦截url
    if (!ret) return true
  }
}

/**
 * URL匹配
 */
function urlMatch(urls, url) {
  // 过滤
  if (urls && urls.length) {
    const ret = urls.some((v) => {
      return url.indexOf(v) == 0
    })

    return ret ? true : false
  }
}
